package com.xbfinal.core;

import com.xbfinal.utils.Constant;
import com.xbfinal.utils.FileUtils;
import com.xbfinal.utils.HttpUtils;

import java.io.*;
import java.net.HttpURLConnection;
import java.util.ArrayList;
import java.util.concurrent.*;

/**
 * @version 1.0
 * @Author 笑霸final
 * @Date 2023/10/18 18:46
 * @注释 下载器类
 */
public class Downloader {

//    private ScheduledExecutorService  scheduled = new ScheduledThreadPoolExecutor(1);
//    private ScheduledExecutorService scheduled = Executors.newScheduledThreadPool(1);
    private ScheduledExecutorService scheduled = Executors.newScheduledThreadPool(1);
    //任务线程池对象
    private ThreadPoolExecutor poolExecutor = new ThreadPoolExecutor(
            Constant.THREAD_NOW,
            Constant.THREAD_NOW,
            0,TimeUnit.SECONDS,
            new ArrayBlockingQueue<>(Constant.THREAD_NOW));

    public void download(String url) {
        //获取文件名
        String httpFileName = HttpUtils.getHttpFileName(url);
        //文件的下载路径
        httpFileName = Constant.PATH+httpFileName;

        //获取本地文件大小
        long localFileLength = FileUtils.getFileSize(httpFileName);

        //获取链接对象
        HttpURLConnection httpUrlConnection = null;
        DownloaderInfo downloaderInfo = null;
        try {
            httpUrlConnection = HttpUtils.getHttpUrlConnection(url);
            //获取下载文件的总大小
            int contentLength = httpUrlConnection.getContentLength();
            //判断文件是否已经下载过？
            if(localFileLength >= contentLength){
                try{
                    System.out.println("已经下载过无须在下载~~~");
                    return;
                }finally {
                    //关闭链接对象
                    httpUrlConnection.disconnect();
                }
            }
            //创建获取下载信息的对象
            downloaderInfo = new DownloaderInfo(contentLength);
//            downloaderInfo.finishedSize=Double.longBitsToDouble(localFileLength) ;
            //监控线程 每1秒执行一次
            scheduled.scheduleAtFixedRate(downloaderInfo,1,1, TimeUnit.SECONDS);
            //切分任务
            ArrayList<Future> list = new ArrayList<>();
            split(url,list);
            //获取集合中的数据
            list.forEach(future -> {
                try {
                    future.get();//方便后续合并文件 所有文件下载未完成会阻塞
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                } catch (ExecutionException e) {
                    throw new RuntimeException(e);
                }
            } );
            //合并文件
            merge(httpFileName);
            //删除临时文件
            clearTemp(httpFileName);


        } catch (IOException e) {
            throw new RuntimeException(e);
        } finally {
            //关闭链接对象
            httpUrlConnection.disconnect();
            scheduled.shutdownNow();
            poolExecutor.shutdownNow();
        }

    }


    /**
     * 文件切分
     * @param url
     * @param futureList
     */
    public void split(String url , ArrayList<Future> futureList){

        try {
            //获取下载文件大小
            long httpFileLength = HttpUtils.getHttpFileLength(url);
            //计算切分后文件的大小
            long size= httpFileLength/Constant.THREAD_NOW;
            //计算分块个数
            for (int i = 0; i < Constant.THREAD_NOW; i++) {
                //下载起始位置
                long startPost = i*size;
                //计算结束位置
                long startEnd;
                if(i==Constant.THREAD_NOW-1){
                    startEnd=0;
                }else{
                    startEnd=startPost+size;
                }
                if(startPost!=0){
                    startPost++;
                }
                //创建任务
                DownloaderTask downloaderTask = new DownloaderTask(url, startPost, startEnd,i);
                //将任务提交到线程池中
                Future<Boolean> submit = poolExecutor.submit(downloaderTask);
                futureList.add(submit);
            }


        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    public boolean merge(String fileName){
        System.out.print("\r");
        System.out.println("开始合并文件");
        byte[] buffer = new byte[Constant.BYTE_SIZE];
        int len = -1;
        try( RandomAccessFile accessFile = new RandomAccessFile(fileName,"rw")){
            for (int i = 0; i < Constant.THREAD_NOW; i++) {
                try( FileInputStream fileInputStream = new FileInputStream(fileName+".temp"+i);
                     BufferedInputStream bis = new BufferedInputStream(fileInputStream)
                ){
                    while ((len = bis.read(buffer)) != -1){
                        accessFile.write(buffer,0,len);
                    }
                }
            }
            System.out.print("\r");
            System.out.println("文件合并完毕");
        } catch (FileNotFoundException e) {
            System.out.println("文件未找到");
            return false;
        } catch (IOException e) {
            System.out.println("未知错误");
            return false;
        }
        return true;
    }

    /**
     * 清空临时文件
     * @param fileName
     * @return
     */
    public boolean clearTemp(String fileName){
        for (int i = 0; i < Constant.THREAD_NOW; i++) {
            File file = new File(fileName + ".temp" + i);
            file.delete();
        }
        return true;
    }
}
